package mylittleinvestigations.GameUi;
import mylittleinvestigations.EasingFunctions.*;
import mylittleinvestigations.MouseHelper;
import mylittleinvestigations.PersistentThreads.RenderThread;
import mylittleinvestigations.Vector2;
import org.dawnmew.jpurewave.SoundSystem;
import org.newdawn.slick.*;
import org.newdawn.slick.geom.*;

public class Arrow
{
    private static final Color NormalColor = Color.white;
    private static final Color MouseOverColor = Color.yellow;
    private static final Color MouseDownColor = Color.red;
    private static final Color DisabledColor = Color.gray;

    private static Image horizontalTexture;
    private static Image verticalTexture;

    private int xPosition;
    private int yPosition;
    private int width;
    private int height;
    private ArrowDirection direction;
    private int bounceDistance;
    private Rectangle hitboxRect;

    private boolean isClickable;
    private boolean isMouseOver;
    private boolean isMouseDown;
    
    private float arrowOffset;
    private GravityBounceEase arrowOffsetEase;

    private String clickSoundEffect="ButtonClick2";
    
    private boolean isEnabled;
    
    public boolean getIsEnabled() { return this.isEnabled; }
    public void setIsEnabled(boolean isEnabled) { this.isEnabled = isEnabled; }
    
    private boolean isClicked;
    
    public boolean getIsClicked() { return this.isClicked; }
    private void setIsClicked(boolean isClicked) { this.isClicked = isClicked; }
    
    public String getClickSoundEffect()
    {
        return this.clickSoundEffect;
    }

    public static void Initialize(Image horizontalTexture, Image verticalTexture)
    {
        Arrow.horizontalTexture = horizontalTexture;
        Arrow.verticalTexture = verticalTexture;
    }

    public Arrow(int xPosition, int yPosition, ArrowDirection direction, int bounceDistance, boolean isClickable)
    {
        this.xPosition = xPosition;
        this.yPosition = yPosition;
        this.direction = direction;

        if (this.direction == ArrowDirection.Up || this.direction == ArrowDirection.Down)
        {
            this.width = verticalTexture.getWidth();
            this.height = verticalTexture.getHeight();
        }
        else
        {
            this.width = horizontalTexture.getWidth();
            this.height = horizontalTexture.getHeight();
        }

        this.bounceDistance = bounceDistance;

        this.hitboxRect = new Rectangle(this.xPosition, this.yPosition, this.width, this.height);

        if (this.direction == ArrowDirection.Up)
        {
            this.hitboxRect.setX(this.hitboxRect.getX() - 5);
            this.hitboxRect.setWidth(this.hitboxRect.getWidth() + 10);
            this.hitboxRect.setY(this.hitboxRect.getY() - bounceDistance);
            this.hitboxRect.setHeight(this.hitboxRect.getHeight() + bounceDistance);
        }
        else if (this.direction == ArrowDirection.Down)
        {
            this.hitboxRect.setX(this.hitboxRect.getX() - 5);
            this.hitboxRect.setWidth(this.hitboxRect.getWidth() + 10);
            this.hitboxRect.setHeight(this.hitboxRect.getHeight() + bounceDistance);
        }
        else if (this.direction == ArrowDirection.Left)
        {
            this.hitboxRect.setY(this.hitboxRect.getY() - 5);
            this.hitboxRect.setHeight(this.hitboxRect.getHeight() + 10);
            this.hitboxRect.setX(this.hitboxRect.getY() - bounceDistance);
            this.hitboxRect.setWidth(this.hitboxRect.getWidth() + bounceDistance);
        }
        else if (this.direction == ArrowDirection.Right)
        {
            this.hitboxRect.setY(this.hitboxRect.getY() - 5);
            this.hitboxRect.setHeight(this.hitboxRect.getHeight() + 10);
            this.hitboxRect.setWidth(this.hitboxRect.getWidth() + bounceDistance);
        }

        this.isClickable = isClickable;
        this.isEnabled = true;

        this.arrowOffset = 0;
        this.arrowOffsetEase = new GravityBounceEase(
                0,
                this.direction == ArrowDirection.Up || this.direction == ArrowDirection.Left ? -this.bounceDistance : this.bounceDistance,
                300);
    }

    public void Update(GameContainer gc, int delta)
    {
        if (!this.arrowOffsetEase.getIsStarted() || this.arrowOffsetEase.getIsFinished())
        {
            this.arrowOffsetEase.Begin();
        }
        
        this.arrowOffsetEase.Update(gc, delta);
        this.arrowOffset = (float)this.arrowOffsetEase.GetCurrentValue();

        this.UpdateState();
    }

    public void UpdateState()
    {
        if (this.isClickable && this.getIsEnabled())
        {
            this.isMouseOver = MouseHelper.MouseOverRect(this.hitboxRect);
            this.isMouseDown = MouseHelper.MouseDownOnRect(this.hitboxRect);
            this.setIsClicked(MouseHelper.ClickedOnRect(this.hitboxRect));

            if (this.isMouseOver || this.isMouseDown)
            {
                MouseHelper.SetToHandCursor();
            }

            if (this.getIsClicked())
            {
                SoundSystem.getInstance().playSound(getClickSoundEffect());
            }
        }
        else
        {
            this.Reset();
        }
    }

    public void Draw(GameContainer gc, Graphics g)
    {
        this.Draw(gc, g, 0);
    }

    public void Draw(GameContainer gc, Graphics g, float xOffset)
    {
        this.Draw(gc, g, xOffset, 0);
    }

    public void Draw(GameContainer gc, Graphics g, float xOffset, float yOffset)
    {
        Color color;

        if (!this.getIsEnabled() && this.isClickable)
        {
            color = DisabledColor;
        }
        else if (this.isMouseDown)
        {
            color = MouseDownColor;
        }
        else if (this.isMouseOver)
        {
            color = MouseOverColor;
        }
        else
        {
            color = NormalColor;
        }

        Vector2 position = new Vector2(xPosition + xOffset, yPosition + yOffset);

        if (this.getIsEnabled())
        {
            if (this.direction == ArrowDirection.Up || this.direction == ArrowDirection.Down)
            {
                position.setY(position.getY() + this.arrowOffset);
            }
            else if (this.direction == ArrowDirection.Left || this.direction == ArrowDirection.Right)
            {
                position.setX(position.getX() + this.arrowOffset);
            }
        }
        
        boolean flipVertically = false;
        boolean flipHorizontally = false;

        if (this.direction == ArrowDirection.Up)
        {
            flipVertically = true;
        }
        else if (this.direction == ArrowDirection.Left)
        {
            flipHorizontally = true;
        }

        Image texture = (this.direction == ArrowDirection.Up || this.direction == ArrowDirection.Down) ? verticalTexture : horizontalTexture;
        RenderThread.getInstance().AddImageToRenderQueue(texture, (float)position.getX(), (float)position.getY(), color, flipHorizontally, flipVertically);
    }

    public void Reset()
    {
        this.isMouseOver = false;
        this.isMouseDown = false;
        this.setIsClicked(false);
    }
}
